﻿
Imports System.Threading

Public MustInherit Class rcEmitterApp(Of emitter_t)
    Private _emitter As emitter_t = Nothing

    Private latency As Int64 = 0
    Private requestCount As Int32 = 0

    Private Shared Function display(ByVal i As Double) As String
        Return i.ToString("F4")
    End Function

    Public Sub New()
        Dim startMs As Int64 = 0
        startMs = Now.milliseconds()
        queueInBackendThread(Of _1000)(
            Sub()
                Console.Write(strcat("total request count ", requestCount,
                                     ", average qps ",
                                     display(requestCount / millisecondsToSeconds(Now.milliseconds() - startMs)),
                                     ", average latency in ms ", display(latency / requestCount),
                                     character.return))
            End Sub)
    End Sub

    Protected MustOverride Function generate(ByVal host As String,
                                             ByVal port As Int64,
                                             Optional ByVal holdtimeMs As Int64 = tcpTalk4.defaultHoldTimeMs,
                                             Optional ByVal livetimeMs As Int64 = tcpTalk4.defaultLiveTimeMs) _
                                            As emitter_t
    Protected MustOverride Sub [single](ByVal input As String,
                                        ByVal result As pointer(Of String),
                                        ByRef ec As eventComb)
    Protected MustOverride Function random() As String

    Protected Function emitter() As emitter_t
        assert(Not _emitter Is Nothing)
        Return _emitter
    End Function

    Private Function [single](ByVal s As String) As eventComb
        Dim ec As eventComb = Nothing
        Dim result As pointer(Of String) = Nothing
        result = New pointer(Of String)()
        Return New eventComb(Function() As Boolean
                                 [single](s, result, ec)
                                 Return waitfor(ec) AndAlso
                                        goto_next()
                             End Function,
                             Function() As Boolean
                                 If ec.end_result() Then
                                     If isdebugbuild() Then
                                         Console.WriteLine(strcat(s, " ==> ", +result))
                                     End If
                                 Else
                                     raiseError(errorHandle.errorType.warning,
                                                "failed to runjob on rcEmitter.")
                                 End If
                                 Return goto_end()
                             End Function)
    End Function

    Private Function run(ByVal d As _do(Of String)) As eventComb
        assert(Not d Is Nothing)
        Dim s As String = Nothing
        Dim startMs As Int64 = 0
        Return New eventComb(Function() As Boolean
                                 startMs = Now.milliseconds()
                                 s = d()
                                 If s Is Nothing Then
                                     Return goto_end()
                                 Else
                                     Return waitfor([single](s)) AndAlso
                                            goto_next()
                                 End If
                             End Function,
                             Function() As Boolean
                                 Interlocked.Increment(requestCount)
                                 Interlocked.Add(latency, Now.milliseconds() - startMs)
                                 If consoleCancelKeyPressed() Then
                                     Return goto_end()
                                 Else
                                     Return goto_prev()
                                 End If
                             End Function)
    End Function

    Public Sub run(ByVal args() As String)
        startmainBase(logfile:=errorHandle.NOLOGFILEMARK)
        counter.initial(counter.NOCOUNTERFILEMARK)
        'managedThreadPool.register()
        threadpool.register()
        callbackManager.register()
        eventDriver.register()
        resolver.global.fix()
        Dim port As Int32 = 0
        If args Is Nothing OrElse args.Length() < 2 OrElse Not convertor.toint32(args(1), port) Then
            raiseError(errorHandle.errorType.user, applicationName(), " {host} {port}")
        Else
            _emitter = generate(args(0), port)
            If args.Length() > 2 Then
                Dim tc As Int64 = 0
                tc = Environment.ProcessorCount() << 2
                If tc > 64 Then
                    tc = 64
                End If
                For i As Int64 = 0 To tc - 1
                    assert_begin(run(AddressOf random))
                Next
            Else
                assert_begin(run(Function() As String
                                     Return Console.ReadLine()
                                 End Function))
            End If
            While Not consoleCancelKeyPressed()
                sleep()
            End While
        End If
        finishmainBase()
    End Sub
End Class
